using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
using TEILib;
using TEIConsole.Properties;



namespace TEIConsole
{
    class TEIMain
    {
        //Parsed command line options
        internal TEIOptions options;
        //nxslt return codes
        internal const int RETURN_CODE_OK = 0;
        internal const int RETURN_CODE_ERROR = -1;
        //Timings
        private TEITimings timings;
        //reporter
        private Reporter reporter;

        public static int Main(string[] args)
        {
            TEIMain teiMain = new TEIMain();
            teiMain.setReporter(new Reporter());
            try
            {
                TEIArgumentsParser clParser = new TEIArgumentsParser();
                teiMain.options = clParser.ParseArguments(args);
                //Ok, then let's process it
                return teiMain.Process();
               
            }
            catch (TEICommandLineParsingException clpe)
            {
                //There was an exception while parsing command line
                teiMain.reporter.ReportCommandLineParsingError(Reporter.GetFullMessage(clpe));
                return RETURN_CODE_ERROR;
            }
            catch (TEIException ne)
            {
                teiMain.reporter.ReportError(Reporter.GetFullMessage(ne));
                return RETURN_CODE_ERROR;
            }
            catch (Exception e)
            {
                //Some other exception
                teiMain.reporter.ReportError(TEIStrings.Error, Reporter.GetFullMessage(e));
                return RETURN_CODE_ERROR;
            }
            //string strDocPath = "C:\\Documents and Settings\\jporter\\My Documents\\xml\\00000089.xml";
            //FixNotes(strDocPath, "//tei:note[@type='endnote']", "//tei:note[@type='marker']");//emph[@rend='Superscript']
            //ValidateLibrary();
        }

        internal void setReporter(Reporter r)
        {
            this.reporter = r;
        }

        /// <summary>
        /// Process command line arguments and applies the specified stylesheet
        /// to the specified source document.
        /// </summary>
        internal int Process()
        {
            //Start timing if needed
            Stopwatch totalTimer = null;
            if (options.ShowTiming)
            {
                timings = new TEITimings();
                totalTimer = new Stopwatch();
                totalTimer.Start();
            }

            //Just show help
            if (options.ShowHelp)
            {
                reporter.ReportUsage();
                return RETURN_CODE_OK;
            }

            if (options.Transform)
            {
                Transform(options.Source, options.Stylesheet, options.ResultPath);
            }

            if (options.Keywords)
            {
                KeywordFrequency(options.Source);
            }

            if (options.MakeBibliography)
            {
                MakeBibliography("C:\\Users\\User\\Documents\\xml");
                
            }

            if (options.Validate)
            {
                Validate(options.LibPath, options.XsdPath, "http://www.tei-c.org/ns/1.0");
            }

            if (options.Summarize)
            {
                Summarize(options.Source);
            }

            if (options.ShowTiming)
            {
                totalTimer.Stop();
                timings.TotalRunTime = totalTimer.ElapsedMilliseconds;
                reporter.ReportTimings(ref timings);
            }
            return RETURN_CODE_OK;
        }

        /// <summary>
        /// Validate a document or library of documents.
        /// </summary>
        /// <param name="sourcePath">The path of the document or library.</param>
        /// <param name="xsdPath">The path of the XSD to use for validation.</param>
        /// <param name="targetNamespace">The target namespace of the schema.</param>
        public static void Validate(string sourcePath, string xsdPath, string targetNamespace)
        {
            if (Directory.Exists(sourcePath))
            {
                TEILibrary objTEILib = new TEILibrary(sourcePath);
                objTEILib.Validate(xsdPath, targetNamespace);
            }
            //TODO: Add the possibility of validating a single document.
            //else if (File.Exists(sourcePath))
            //{
            //    TEIDocument objTEIDoc = new TEIDocument(sourcePath);
            //    objTEIDoc.Validate(sourcePath, resultPath);
            //}
        }

        /// <summary>
        /// Get the keyword and it's frequency from a given document or library.
        /// </summary>
        /// <param name="source">The path of the document or library.</param>
        public static void KeywordFrequency(string source)
        {
            Hashtable keywords = new Hashtable();

            if (File.Exists(source))
            {
                TEIDocument objTEIDoc = new TEIDocument(source);
                keywords = objTEIDoc.WordFrequency();
            }

            if (Directory.Exists(source))
            {
                TEILibrary objTEILib = new TEILibrary(source);
                keywords = objTEILib.WordFrequency();
                //Console.WriteLine(objTEILib.);
            }

            foreach (DictionaryEntry word in keywords)
            {
                Console.WriteLine("{0} {1}", word.Key, word.Value);
            }
        }

        /// <summary>
        /// Summarize a document or library.
        /// </summary>
        /// <param name="sourcePath">The document or library path to summarize.</param>
        public static void Summarize(string sourcePath)
        {
            TEIDocument objTEIDoc = new TEIDocument(sourcePath);
            Console.WriteLine(objTEIDoc.Summary());
        }

        /// <summary>
        /// Transform a document or library of documents.
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="xslPath"></param>
        /// <param name="resultPath"></param>
        public static void Transform(string sourcePath, string xslPath, string resultPath)
        {
            if (Directory.Exists(sourcePath))
            {
                TEILibrary objTEILib = new TEILibrary(sourcePath);
                objTEILib.Transform(xslPath, resultPath);
            }
            else if (File.Exists(sourcePath))
            {
                TEIDocument objTEIDoc = new TEIDocument(sourcePath);
                objTEIDoc.Transform(xslPath, resultPath);
            }
        }

        /// <summary>
        /// Replaces a marker node with a content node in an XML document.
        /// </summary>
        /// <param name="source">The path of the source document.</param>
        /// <param name="contentList">The XPath statement to get teh content nodes.</param>
        /// <param name="markerList">The XPath statement to get the marker nodes.</param>
        public static void ReplaceMarkerWithContent(string source, string contentList, string markerList)
        {
            //string strDocPath = "C:\\Documents and Settings\\jporter\\My Documents\\xml\\";

            //create a new document
            TEIDocument objTEIDoc = new TEIDocument(source);

            XmlNodeList objContent = objTEIDoc.getNodeList(contentList);//("//tei:note");
            XmlNodeList objMarker = objTEIDoc.getNodeList(markerList);//("//tei:emph[@rend='Superscript']");

            //do the replace
            int i = 0;
            
            foreach (XmlNode objNode in objContent)
            {
                XmlNode objParent = objMarker.Item(i).ParentNode;
                XmlNode objNodeDel = objMarker.Item(i);
                objParent.ReplaceChild(objNode, objNodeDel);

                ////replace the xref element with the note contents
                //objEmph.Item(i).InnerXml = objNode.InnerXml;
                ////set the name
                //objEmph.Item(i).Name = objNode.Name;
                ////remove the attributes
                //objEmph.Item(i).Attributes.RemoveAll();
                ////add the appropriate attributes
                //foreach(XmlAttribute objAttribute in objNode.Attributes)
                //{
                //    objEmph.Item(i).Attributes.Append(objAttribute);
                //}
                i++;
            }

            //save the fixed document
            objTEIDoc.Save(Path.GetDirectoryName(objTEIDoc.FullFilePath) + "\\" + objTEIDoc.idno + "fixed.xml");
        }

        /// <summary>
        /// Create a bibliography document from the given library.
        /// </summary>
        public void MakeBibliography(string strBibPath)
        {
            TEILibrary objTEILib = new TEILibrary(strBibPath);
            ArrayList arrAuthor = new ArrayList();
            
            arrAuthor.Insert(0, "Jeremy Porter");
            objTEILib.createBibliography(strBibPath, arrAuthor);

            //objTEILib.createBibliography("C:\\Documents and Settings\\jporter\\My Documents\\bibliography.xml", arrAuthor);
            //objTEILib.CreateListOfNotes("C:\\Documents and Settings\\jporter\\My Documents\\ListOfNotes.xml", arrAuthor);

        }

        public static void WalkNode2(XPathNavigator nav, ref string output)
        {
            // display the node information in a pretty format
            //DisplayNode(nav);
            //string val = "";
            if (nav.NodeType == XPathNodeType.Text)
            {
                //val = nav.Value;
                output = output + nav.Value;
                //Console.WriteLine(nav.Value);
            }
            //Console.WriteLine("Name:{0} Type:{1} Value:{2}",
            //     nav.Name, nav.NodeType, val);

            // process child attribute nodes
            //if (nav.HasAttributes)
            //{
            //    // loop through all the attributes of the 
            //    // current node
            //    // and display them
            //    while (nav.MoveToNextAttribute())
            //        DisplayNode(nav);

            //    // move back to the parent element node of the
            //    // attribute nodes
            //    nav.MoveToParent();
            //}

            // process child element nodes
            if (nav.HasChildren)
            {
                // move to the first child of the 
                // current node
                nav.MoveToFirstChild();

                // recursively display the first child node
                // and its subnodes
                WalkNode2(nav, ref output);

                // loop through the rest of the siblings
                // recursively
                while (nav.MoveToNext())
                    WalkNode2(nav, ref output);

                // move back to the original parent node
                nav.MoveToParent();
            }
        }

        
        public void GetTextFromDoc()
        {
            XPathNavigator nav;
            XPathDocument docNav;
            string strText = "";
            docNav = new XPathDocument(@"C:\Documents and Settings\jporter\My Documents\xml\00000001.xml");
            nav = docNav.CreateNavigator();
            nav.MoveToRoot();

            //Move to the first child node (comment field).
            nav.MoveToFirstChild();

            do
            {
                //Find the first element.
                if (nav.NodeType == XPathNodeType.Element)
                {
                    //Determine whether children exist.
                    if (nav.HasChildren == true)
                    {
                        //Move to the first child.
                        nav.MoveToFirstChild();

                        //Loop through all of the children.
                        do
                        {
                            //only process text elements
                            if (nav.NodeType == XPathNodeType.Text)
                            {
                                //Display the data.
                                //Console.Write("The XML string for this child ");
                                strText = nav.Value + " ";
                                Console.WriteLine(strText);

                                //Check for attributes.
                                //if (nav.HasAttributes == true)
                                //{
                                //    Console.WriteLine("This node has attributes");
                                //}
                            }
                        } while (nav.MoveToNext());
                    }
                }
            } while (nav.MoveToNext());
        }
    }
}


/**********************
 * #region using
using System;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Xml.Schema;
using System.Xml;
using System.IO;
using System.Net;
using System.Text;
using System.Diagnostics;
using Mvp.Xml.XInclude;
using Mvp.Xml.Common.Xsl;
using System.Reflection;
using System.CodeDom.Compiler;
#endregion

namespace XmlLab.nxslt
{
    /// <summary>
    /// nxslt main class.
    /// </summary>
    public class NXsltMain
    {
        //Parsed command line options
        internal NXsltOptions options;
        //nxslt return codes
        internal const int RETURN_CODE_OK = 0;
        internal const int RETURN_CODE_ERROR = -1;
        //Timings
        private NXsltTimings timings;
        //reporter
        private Reporter reporter;

        /// <summary>
        /// nxslt main entry point.
        /// </summary>
        /// <param name="args">Command line args</param>
        public static int Main(string[] args)
        {
            NXsltMain nxsltMain = new NXsltMain();
            nxsltMain.setReporter(new Reporter());
            try
            {                                
                NXsltArgumentsParser clParser = new NXsltArgumentsParser();
                nxsltMain.options = clParser.ParseArguments(args);                
                //Ok, then let's process it
                return nxsltMain.Process();
            }
            catch (NXsltCommandLineParsingException clpe)
            {
                //There was an exception while parsing command line
                nxsltMain.reporter.ReportCommandLineParsingError(Reporter.GetFullMessage(clpe));
                return RETURN_CODE_ERROR;
            }
            catch (NXsltException ne)
            {
                nxsltMain.reporter.ReportError(Reporter.GetFullMessage(ne));
                return RETURN_CODE_ERROR;
            }
            catch (Exception e)
            {
                //Some other exception
                nxsltMain.reporter.ReportError(NXsltStrings.Error, Reporter.GetFullMessage(e));
                return RETURN_CODE_ERROR;
            }
        }// Main() method

        internal void setReporter(Reporter r)
        {
            this.reporter = r;
        }

        /// <summary>
        /// Process command line arguments and applies the specified stylesheet
        /// to the specified source document.
        /// </summary>
        internal int Process()
        {
            //Start timing if needed
            Stopwatch totalTimer = null;
            if (options.ShowTiming)
            {
                timings = new NXsltTimings();
                totalTimer = new Stopwatch();
                totalTimer.Start();
            }

            //Just show help
            if (options.ShowHelp)
            {
                reporter.ReportUsage();
                return RETURN_CODE_OK;
            }

            //Check that everything is in place
            if (options.Source == null && !options.LoadSourceFromStdin && !options.NoSourceXml)
            {
                reporter.ReportCommandLineParsingError(NXsltStrings.ErrorMissingSource);
                return RETURN_CODE_ERROR;
            }
            if (options.Stylesheet == null && !options.LoadStylesheetFromStdin
              && !options.GetStylesheetFromPI && !options.PrettyPrintMode)
            {
                //No stylesheet - run identity transform
                options.IdentityTransformMode = true;
            }
            if (options.PrettyPrintMode &&
              (options.Stylesheet != null || options.LoadStylesheetFromStdin || options.GetStylesheetFromPI))
            {
                reporter.ReportCommandLineParsingError(NXsltStrings.ErrorStylesheetAndPrettyPrintMode);
                return RETURN_CODE_ERROR;
            }

            //Prepare source XML reader
            XmlResolver srcResolver = null;
            if (options.ResolveExternals)
            {
                srcResolver = Utils.GetXmlResolver(options.SourceCredential, options, false);
            }
            XmlReader srcReader = PrepareSourceReader(srcResolver);
            if (options.PrettyPrintMode)
            {
                //Process in pretty-print mode
                Utils.PrettyPrint(srcReader, options);
            }
            else
            {
                //Process transformation         
                XmlResolver stylesheetResolver = Utils.GetXmlResolver(options.XSLTCredential, options, true);

                if (options.GetStylesheetFromPI)
                {
                    //To get stylesheet from the PI we load source XML into
                    //XPathDocument (consider embedded stylesheet)
                    XPathDocument srcDoc = new XPathDocument(srcReader, XmlSpace.Preserve);
                    XPathNavigator srcNav = srcDoc.CreateNavigator();
                    //Now srcReader reads in-memory cache instead
                    srcReader = srcNav.ReadSubtree();
                    MvpXslTransform xslt = PrepareStylesheetFromPI(srcNav, stylesheetResolver);
                    Transform(srcReader, xslt, srcResolver);
                }
                else
                {
                    MvpXslTransform xslt = PrepareStylesheet(stylesheetResolver);
                    Transform(srcReader, xslt, srcResolver);
                }
            }

            if (options.ShowTiming)
            {
                totalTimer.Stop();
                timings.TotalRunTime = totalTimer.ElapsedMilliseconds;
                reporter.ReportTimings(ref timings);
            }
            return RETURN_CODE_OK;
        }

        /// <summary>
        /// Performs XSL Transformation.
        /// </summary>
        private void Transform(XmlReader srcReader, MvpXslTransform xslt, XmlResolver resolver)
        {
            Stopwatch transformTimer = null;
            if (options.ShowTiming)
            {
                transformTimer = new Stopwatch();
                transformTimer.Start();
            }
            if (options.OutFile != null)
            {
                //Transform to a file
                FileStream fs;
                try
                {
                    fs = File.Open(options.OutFile, FileMode.Create);
                }
                catch
                {
                    throw new NXsltException(NXsltStrings.ErrorCreatingFile, options.OutFile);
                }
                try
                {
                    XmlOutput results = new XmlOutput(fs);
                    results.XmlResolver = new OutputResolver(Path.GetDirectoryName(options.OutFile));
                    TransformImpl(srcReader, xslt, resolver, results);
                }
                finally
                {
                    fs.Close();
                }
            }
            else
            {
                //Transform to Console
                XmlOutput results = new XmlOutput(Console.Out);
                results.XmlResolver = new OutputResolver(Directory.GetCurrentDirectory());
                TransformImpl(srcReader, xslt, resolver, results);
            }
            //Save transfomation time
            if (options.ShowTiming)
            {
                transformTimer.Stop();
                timings.XsltExecutionTime = transformTimer.ElapsedMilliseconds;
            }
        }

        /// <summary>
        /// Actual transformation and error handling.
        /// </summary>    
        private void TransformImpl(XmlReader srcReader, MvpXslTransform xslt, XmlResolver resolver, XmlOutput results)
        {
            xslt.MultiOutput = options.MultiOutput;
            try
            {
                xslt.Transform(new XmlInput(srcReader, resolver), options.XslArgList, results);
            }
            catch (XmlException xe)
            {
                string uri = options.LoadSourceFromStdin ? NXsltStrings.FromStdin : xe.SourceUri;
                throw new NXsltException(NXsltStrings.ErrorParsingDoc, uri, Reporter.GetFullMessage(xe));
            }
            catch (XmlSchemaValidationException ve)
            {
                string uri = options.LoadSourceFromStdin ? NXsltStrings.FromStdin : srcReader.BaseURI;
                throw new NXsltException(NXsltStrings.ErrorParsingDoc, uri, Reporter.GetFullMessage(ve));
            }
            catch (Exception e)
            {
                throw new NXsltException(NXsltStrings.ErrorTransform, Reporter.GetFullMessage(e));
            }

        }

        /// <summary>
        /// Prepares, loads and compiles XSLT stylesheet.
        /// </summary>    
        private MvpXslTransform PrepareStylesheet(XmlResolver stylesheetResolver)
        {
            Stopwatch xsltCompileTimer = null;
            if (options.ShowTiming)
            {
                xsltCompileTimer = new Stopwatch();
                xsltCompileTimer.Start();
            }

            XmlReader stylesheetReader = PrepareStylesheetReader(stylesheetResolver);
            MvpXslTransform xslt = CreateTransform(stylesheetResolver, stylesheetReader);

            //Save stylesheet loading/compilation time
            if (options.ShowTiming)
            {
                xsltCompileTimer.Stop();
                timings.XsltCompileTime = xsltCompileTimer.ElapsedMilliseconds;
            }

            return xslt;
        }

        // Cached value of Environment.CurrentDirectory
        private string currentDir = null;

        /// 
        /// Returns user-friendly file name. First, it tries to obtain a file name
        /// from the given uriString.
        /// Then, if fullPaths == false, and the file name starts with the current
        /// directory path, it removes that path from the file name.
        /// 
        private string GetFriendlyFileName(string uriString)
        {
            Uri uri;

            if (uriString == null ||
                uriString.Length == 0 ||
                !Uri.TryCreate(uriString, UriKind.Absolute, out uri) ||
                !uri.IsFile
            )
            {
                return uriString;
            }

            string fileName = uri.LocalPath;

            if (true)
            //if (!fullPaths)
            {
                if (currentDir == null)
                {
                    currentDir = Environment.CurrentDirectory;
                    if (currentDir[currentDir.Length - 1] != Path.DirectorySeparatorChar)
                    {
                        currentDir += Path.DirectorySeparatorChar;
                    }
                }

                if (fileName.StartsWith(currentDir, StringComparison.OrdinalIgnoreCase))
                {
                    fileName = fileName.Substring(currentDir.Length);
                }
            }

            return fileName;
        }

        private string GetCompileErrors(XslCompiledTransform xslt)
        {
            try
            {
                MethodInfo methErrors = typeof(XslCompiledTransform).GetMethod(
                    "get_Errors", BindingFlags.NonPublic | BindingFlags.Instance);

                if (methErrors == null)
                {
                    return null;
                }

                CompilerErrorCollection errorColl =
                    (CompilerErrorCollection)methErrors.Invoke(xslt, null);
                StringBuilder sb = new StringBuilder();

                foreach (CompilerError error in errorColl)
                {
                    sb.AppendFormat("{0}({1},{2}) : {3} {4}: {5}",
                        GetFriendlyFileName(error.FileName),
                        error.Line,
                        error.Column,
                        error.IsWarning ? "warning" : "error",
                        error.ErrorNumber,
                        error.ErrorText
                    );
                    sb.AppendLine();
                }
                return sb.ToString();
            }
            catch
            {
                // MethodAccessException or SecurityException may happen 
                //if we do not have enough permissions
                return null;
            }
        }

        /// <summary>
        /// Creates XslCompiledTransform instance for given reader and resolver.
        /// </summary>                
        private MvpXslTransform CreateTransform(XmlResolver stylesheetResolver, XmlReader stylesheetReader)
        {            
            MvpXslTransform xslt = new MvpXslTransform();
            xslt.SupportCharacterMaps = options.ProcessCharacterMaps;
            xslt.EnforceXHTMLOutput = options.EnforceXhtmlOutput;
            try
            {
                xslt.Load(stylesheetReader, XsltSettings.TrustedXslt, stylesheetResolver);
            }
            catch (XsltException xslte)
            {
                string errors = GetCompileErrors(xslt.CompiledTransform);
                if (!string.IsNullOrEmpty(errors))
                {
                    errors += Environment.NewLine;
                }
                errors += Reporter.GetFullMessage(xslte);
                throw new NXsltException(errors);
            }
            catch (XmlException xe)
            {
                string uri = options.LoadStylesheetFromStdin ? NXsltStrings.FromStdin : xe.SourceUri;
                throw new NXsltException(NXsltStrings.ErrorParsingDoc, uri, Reporter.GetFullMessage(xe));
            }
            catch (Exception e)
            {
                string uri = options.LoadStylesheetFromStdin ? NXsltStrings.FromStdin : stylesheetReader.BaseURI;
                throw new NXsltException(NXsltStrings.ErrorCompileStyle, uri, Reporter.GetFullMessage(e));
            }
            return xslt;
        }

        /// <summary>
        /// Prepares, loads and compiles XSLT stylesheet referenced in the PI.
        /// </summary>    
        private MvpXslTransform PrepareStylesheetFromPI(XPathNavigator srcNav, XmlResolver stylesheetResolver)
        {
            Stopwatch xsltCompileTimer = null;
            if (options.ShowTiming)
            {
                xsltCompileTimer = new Stopwatch();
                xsltCompileTimer.Start();
            }
            XPathNavigator pi = srcNav.SelectSingleNode("/processing-instruction('xml-stylesheet')");
            if (pi == null)
            {
                //Absent xml-stylesheet PI
                throw new NXsltException(NXsltStrings.ErrorInvalidPI);
            }
            //Found PI node, look for the href pseudo attribute
            string href = Utils.ExtractStylsheetHrefFromPI(pi);

            MvpXslTransform xslt = null;

            if (href.StartsWith("#"))
            {
                //Embedded stylesheet
                string id = href.Remove(0, 1);
                XPathNavigator embStylesheet = srcNav.SelectSingleNode("id('" + id + "')|/descendant::*[@id='" + id + "']");
                if (embStylesheet == null)
                {
                    //Unresolvable stylesheet URI                    
                    throw new NXsltException(NXsltStrings.ErrorPIStylesheetNotFound, href);
                }
                xslt = CreateTransform(stylesheetResolver, embStylesheet.ReadSubtree());
            }
            else
            {
                //External stylesheet
                options.Stylesheet = href;
                xslt = PrepareStylesheet(stylesheetResolver);
            }
            //Save stylesheet loading/compilation time
            if (options.ShowTiming)
            {
                xsltCompileTimer.Stop();
                timings.XsltCompileTime = xsltCompileTimer.ElapsedMilliseconds;
            }
            return xslt;
        }



        /// <summary>
        /// Prepares source XML reader.
        /// </summary>
        /// <returns>XmlReader over source XML</returns>
        private XmlReader PrepareSourceReader(XmlResolver srcResolver)
        {
            XmlReaderSettings srcReaderSettings = new XmlReaderSettings();
            srcReaderSettings.ProhibitDtd = false;
            if (options.StripWhiteSpace || options.PrettyPrintMode)
            {
                srcReaderSettings.IgnoreWhitespace = true;
            }
            if (options.ValidateDocs)
            {
                srcReaderSettings.ValidationType = ValidationType.DTD;
            }
            srcReaderSettings.XmlResolver = srcResolver;
            XmlReader srcReader;
            if (options.NoSourceXml)
            {
                //No source XML - create dummy one
                srcReader = XmlReader.Create(new StringReader("<dummy/>"), srcReaderSettings);
            }
            else if (options.LoadSourceFromStdin)
            {
                //Get source from stdin 
                srcReader = Utils.CreateReader(Console.OpenStandardInput(), srcReaderSettings, options, srcResolver);
            }
            else
            {
                //Get source from URI
                srcReader = Utils.CreateReader(options.Source, srcReaderSettings, options, srcResolver);
            }
            //Chain schema validaring reader on top
            if (options.ValidateDocs)
            {
                srcReaderSettings.ValidationType = ValidationType.Schema;
                srcReaderSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
                return XmlReader.Create(srcReader, srcReaderSettings);
            }
            return srcReader;
        }

        /// <summary>
        /// Prepares stylesheet XML reader.
        /// </summary>
        /// <returns>XmlReader over source XML</returns>
        private XmlReader PrepareStylesheetReader(XmlResolver stylesheetResolver)
        {
            XmlReaderSettings stylesheetReaderSettings = new XmlReaderSettings();
            stylesheetReaderSettings.ProhibitDtd = false;
            if (options.ValidateDocs)
            {
                stylesheetReaderSettings.ValidationType = ValidationType.DTD;
            }
            if (options.StripWhiteSpace)
            {
                stylesheetReaderSettings.IgnoreWhitespace = true;
            }
            if (!options.ResolveExternals)
                stylesheetReaderSettings.XmlResolver = null;
            else
            {
                stylesheetReaderSettings.XmlResolver = stylesheetResolver;
            }
            XmlReader stylesheetReader;
            if (options.IdentityTransformMode)
            {
                //No XSLT - use identity transformation                
                stylesheetReader = XmlReader.Create(new StringReader(NXsltStrings.IdentityTransformation), stylesheetReaderSettings);
            }
            else if (options.LoadStylesheetFromStdin)
            {
                //Get stylesheet from stdin            
                if (options.ProcessXIncludeInXSLT)
                {
                    XIncludingReader xir = new XIncludingReader(Directory.GetCurrentDirectory(),
                        Console.OpenStandardInput(), stylesheetResolver);
                    xir.XmlResolver = stylesheetResolver;
                    stylesheetReader = XmlReader.Create(xir, stylesheetReaderSettings);
                }
                else
                {
                    stylesheetReader = XmlReader.Create(Console.OpenStandardInput(), stylesheetReaderSettings);
                }
            }
            else
            {
                //Get source from URI
                if (options.ProcessXIncludeInXSLT)
                {
                    XIncludingReader xir = new XIncludingReader(options.Stylesheet,
                        (stylesheetResolver != null && stylesheetResolver is XmlLab.nxslt.Utils.DTDAllowingResolver) ? new XmlUrlResolver() : stylesheetResolver);
                    xir.XmlResolver = stylesheetResolver;
                    stylesheetReader = XmlReader.Create(xir, stylesheetReaderSettings);
                }
                else
                {                    
                    stylesheetReader = XmlReader.Create(options.Stylesheet, stylesheetReaderSettings);
                }
            }
            //Chain schema validaring reader on top
            if (options.ValidateDocs)
            {
                stylesheetReaderSettings.ValidationType = ValidationType.Schema;
                stylesheetReaderSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
                return XmlReader.Create(stylesheetReader, stylesheetReaderSettings);
            }
            return stylesheetReader;
        }


    }// NXsltMain class    
}// XmlLab.nxslt namespace

**********************/